import { dev, manifest } from "@/env.js"
import { ensureSuffix } from "@/utils.js"
import { readFileSync } from "node:fs"
import { join, resolve } from "node:path"

export const resolvePromptReplaces = (raw: string, replaces: Record<string, string>) => {
  return raw.replace(/\$\{([^}]+)\}/g, (match, key) => (key in replaces ? replaces[key] : match))
}

/**
 * 读取指定目录下的提示词文件，支持语言回退。
 *
 * 1. 尝试读取 promptsDir/<language>/<fileName>。
 * 2. 若文件不存在且 language !== "zh"，则自动回退到 promptsDir/zh/<fileName>。
 * 3. 若回退文件也不存在，则抛出原始错误。
 *
 * @param promptsDir 提示词目录的绝对路径
 * @param language 语言代码，例如 "zh"、"en"
 * @param fileName 文件名（含后缀）
 * @param encoding 文件编码
 * @returns 文件内容字符串
 */
export const readPromptFile = (
  promptsDir: string,
  language: string,
  fileName: string,
  encoding: BufferEncoding,
) => {
  const tryPath = (dir: string, file: string) => join(dir, file)
  try {
    // 如果语言是中文，直接放在 promptsDir 下
    if (language === "zh") {
      return readFileSync(tryPath(promptsDir, fileName), encoding)
    }
    // 否则尝试语言子目录
    return readFileSync(tryPath(join(promptsDir, language), fileName), encoding)
  } catch (err) {
    // 如果非中文且失败，回退到中文版本
    if (language !== "zh") {
      try {
        return readFileSync(tryPath(promptsDir, fileName), encoding)
      } catch {
        // 如果中文版本也不存在，抛出原始错误
        throw err
      }
    }
    throw err
  }
}

/**
 * 读取提示词文件并替换占位符。
 *
 * 1. 支持多语言提示词目录: prompts/<language>/<name>.md。
 * 2. 如果指定语言的提示词不存在, 自动回退到中文(zh)版本。
 * 3. 提供占位符替换功能, 将 ${key} 替换为对应的值。
 * 4. 所有选项均为可选, 未提供时使用默认值(replaces = {}, encoding = "utf8", language = "zh")。
 */
export function readPrompt(
  name: string,
  options?: { replaces?: Record<string, string>; encoding?: BufferEncoding; language?: string },
) {
  const resourcesDir = dev
    ? resolve(import.meta.dirname, "..", "..", "docs", "resources")
    : resolve("node_modules", manifest.name, "docs", "resources")

  const { replaces = {}, encoding = "utf8", language = "zh" } = options || {}
  const raw = readPromptFile(resourcesDir, language, ensureSuffix(name, ".md"), encoding)
  return resolvePromptReplaces(raw, replaces)
}
